/*******************************************************************************
SightKit.cpp

	Author:		LiuDingXi
	e-mail:		liudx@gmail.com
	Date time:	2009-08-07

	Copyright (C) 2009
	All rights reserved.
	
*******************************************************************************/
#include "StdAfx.h"
#include "SightKit.h"
#include "SceneDat.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

////////////////////////////////////////////////////////////////////////////////

CSightKit::CSightKit()
{
	m_nStyles = 0;
	m_pStyles = NULL;
}

CSightKit::~CSightKit()
{
	Free();
}


BOOL CSightKit::Load(CArchive& ar)
{
	TCHAR szFolder[MAX_PATH];
	 _tcscpy(szFolder, ar.GetFile()->GetFilePath());
	 LPTSTR pTail = PathFindFileName(szFolder);
	 if(pTail)
	 {
		 *pTail = 0;
	 }

	GROUP* pGroup = NULL;
	
	CString s;
	while(ar.ReadString(s))
	{
		if(s.IsEmpty())
			continue;
		
		LPCTSTR p = s;
		MoveToBegin(p);
		
		#define IS_TAG(tag)	_tcsnicmp(p, tag, _tcslen(tag)) == 0
		
		if(IS_TAG(_T("import")))
		{
			p += 6;
			CString szFile = ParseOf(p);

			TCHAR szFileName[MAX_PATH];
			_tcscpy(szFileName, szFolder);
			PathAppend(szFileName, szFile);

			if(PathFileExists(szFileName))
			{
				LPCTSTR pExt = PathFindExtension(szFileName);
				if(pExt)
				{
					if(_tcsicmp(pExt, _T(".spr")) == 0)
					{
						SKIT* pSkit = new SKIT;
						pSkit->szFile = szFile;
						m_SprKits.push_back(pSkit);

						CFile file(szFileName, CFile::modeRead);
						CArchive spr(&file, CArchive::load);
						pSkit->Load(spr);
					}
					else if(_tcsicmp(pExt, _T(".dlg")) == 0)
					{
						DKIT* pDkit = new DKIT;
						pDkit->SetSightKit(this);
						pDkit->szFile = szFile;
						m_DlgKits.push_back(pDkit);

						CFile file(szFileName, CFile::modeRead);
						CArchive dlg(&file, CArchive::load);
						pDkit->Load(dlg);
					}
					else if(_tcsicmp(pExt, _T(".map")) == 0)
					{
						MKIT* pMkit = new MKIT;
						pMkit->szFile = szFile;
						m_MapKits.push_back(pMkit);

						CFile file(szFileName, CFile::modeRead);
						CArchive map(&file, CArchive::load);
						pMkit->Load(map);
					}
				}
			}
			else
			{
				return FALSE;
			}
		}
		else if(IS_TAG(_T("sight")))
		{
			p += 5;
			m_szName = ParseOf(p);
		}
		else if(IS_TAG(_T("group")))
		{
			pGroup = NewGroup(p + 5);
		}
		else if(IS_TAG(_T("map")))
		{
			if(pGroup != NULL)
			{
				TOBJECT* pObject = pGroup->AddObject(p + 3, tMap);
				if(!LinkObject(pObject))
				{
					printf("map %s NOT FOUND %s\n", pGroup->szName, pObject->szName);
					return FALSE;
				}
			}
		}
		else if(IS_TAG(_T("sprite")))
		{
			if(pGroup != NULL)
			{
				TOBJECT* pObject = pGroup->AddObject(p + 6, tSprite);
				if(!LinkObject(pObject))
				{
					printf("sprite %s NOT FOUND %s\n", pGroup->szName, pObject->szName);
					return FALSE;
				}
			}
		}
		else if(IS_TAG(_T("dialog")))
		{
			if(pGroup != NULL)
			{
				TOBJECT* pObject = pGroup->AddObject(p + 6, tDialog);
				if(!LinkObject(pObject))
				{
					printf("dialog %s NOT FOUND %s\n", pGroup->szName, pObject->szName);
					return FALSE;
				}
			}
		}

	}	
	return TRUE;
}

BOOL CSightKit::Store(CArchive& ar)
{
	if(m_MapKits.size() > 0)
	{
		list<MKIT*>::iterator it;
		it = m_MapKits.begin();
		while(it != m_MapKits.end())
		{
			MKIT* pMkit = *it++;
			CString szImport(_T("import\t"));
			szImport += pMkit->szFile;
			szImport += _T("\r\n");
			ar.WriteString(szImport);
		}
	}
	if(m_SprKits.size() > 0)
	{
		list<SKIT*>::iterator it;
		it = m_SprKits.begin();
		while(it != m_SprKits.end())
		{
			SKIT* pSkit = *it++;
			CString szImport(_T("import\t"));
			szImport += pSkit->szFile;
			szImport += _T("\r\n");
			ar.WriteString(szImport);
		}
	}

	if(m_DlgKits.size() > 0)
	{
		list<DKIT*>::iterator it;
		it = m_DlgKits.begin();
		while(it != m_DlgKits.end())
		{
			DKIT* pDkit = *it++;
			CString szImport(_T("import\t"));
			szImport += pDkit->szFile;
			szImport += _T("\r\n");
			ar.WriteString(szImport);
		}
	}

	CString szSeparator(_T("\r\n\r\n"));
	ar.WriteString(szSeparator);

	CString szSight(_T("sight\t"));
	szSight += m_szName;
	szSight += _T("\r\n");
	ar.WriteString(szSight);

	list<GROUP*>::iterator git;
	git = m_Groups.begin();
	while(git != m_Groups.end())
	{
		GROUP* pGroup = *git++;
		
		CString szGroup(_T("\tgroup\t"));
		szGroup += pGroup->szName + _T("\r\n");
		
		ar.WriteString(szGroup);
		
		list<TOBJECT*>::iterator it;
		it = pGroup->ObjList.begin();
		while(it != pGroup->ObjList.end())
		{
			TOBJECT* pObj = *it++;

			CString szObject;
			switch(pObj->nType)
			{
			case tMap:
				szObject = _T("\t\tmap\t");
				break;
			case tSprite:
				szObject = _T("\t\tsprite\t");
				break;
			case tDialog:
				szObject = _T("\t\tdialog\t");
				break;
			}
			if(!szObject.IsEmpty())
			{
				szObject += pObj->szName + _T("\t");
				szObject += _T("\r\n");
				ar.WriteString(szObject);
			}
		}
		ar.WriteString(szSeparator);
	}

	return TRUE;
}

BOOL CSightKit::Free()
{
	if(m_Groups.size() > 0)
	{
		list<GROUP*>::iterator it;
		it = m_Groups.begin();
		while(it != m_Groups.end())
		{
			GROUP* pGroup = *it++;

			list<TOBJECT*>::iterator lit;
			lit = pGroup->ObjList.begin();
			while(lit != pGroup->ObjList.end())
			{
				TOBJECT* pObject = *lit++;
				delete pObject;
			}
			delete pGroup;
		}
		m_Groups.clear();
	}

	if(m_SprKits.size() > 0)
	{
		list<SKIT*>::iterator it;
		it = m_SprKits.begin();
		while(it != m_SprKits.end())
		{
			SKIT* pSkit = *it++;
			delete pSkit;
		}
		m_SprKits.clear();
	}

	if(m_DlgKits.size() > 0)
	{
		list<DKIT*>::iterator it;
		it = m_DlgKits.begin();
		while(it != m_DlgKits.end())
		{
			DKIT* pDkit = *it++;
			delete pDkit;
		}
		m_DlgKits.clear();
	}

	if(m_MapKits.size() > 0)
	{
		list<MKIT*>::iterator it;
		it = m_MapKits.begin();
		while(it != m_MapKits.end())
		{
			MKIT* pMkit = *it++;
			delete pMkit;
		}
		m_MapKits.clear();
	}

	delete[] m_pStyles;
	m_pStyles = NULL;
	m_nStyles = 0;

	return TRUE;
}

CSightKit::GROUP* CSightKit::NewGroup(LPCTSTR p)
{
	GROUP* pGroup = new GROUP;
	m_Groups.push_back(pGroup);

	pGroup->nType = tGroup;

	pGroup->szName = ParseOf(p);

	return pGroup;
}

CSightKit::TOBJECT* CSightKit::GROUP::AddObject(LPCTSTR p, UINT nType)
{
	TOBJECT* pObject = new TOBJECT;
	pObject->nType = nType;
	pObject->szName = ParseOf(p);
	pObject->pPoint = NULL;
	pObject->nPosX = ParseOf(p, 0);
	pObject->nPosY = ParseOf(p, 0);

	ObjList.push_back(pObject);

	return pObject;
}

BOOL CSightKit::LinkObject(CSightKit::TOBJECT* pObject)
{
	switch(pObject->nType)
	{
	case tSprite:
		{
			SPRITE* pSprite = FindSprite(pObject->szName);
			if(pSprite)
			{
				pObject->pSprite = pSprite;
				return TRUE;
			}
		}
		break;
	case tDialog:
		{
			DIALOG* pDialog = FindDialog(pObject->szName);
			if(pDialog)
			{
				pObject->pDialog = pDialog;
				return TRUE;
			}
		}
		break;
	case tMap:
		{
			TMAP* pMap = FindMap(pObject->szName);
			if(pMap)
			{
				pObject->pMap = pMap;
				return TRUE;
			}
		}
		break;
	}
	return FALSE;
}

CSpriteKit::SPRITE* CSightKit::FindSprite(LPCTSTR szName)
{
	list<SKIT*>::iterator it;
	it = m_SprKits.begin();
	while(it != m_SprKits.end())
	{
		SKIT* pSkit = *it++;
		SPRITE* pSprite = pSkit->FindSprite(szName);
		if(pSprite != NULL)
		{
			return pSprite;
		}
	}
	return NULL;
}

CDialogKit::DIALOG* CSightKit::FindDialog(LPCTSTR szName)
{
	list<DKIT*>::iterator it;
	it = m_DlgKits.begin();
	while(it != m_DlgKits.end())
	{
		DKIT* pDkit = *it++;
		DIALOG* pDialog = pDkit->FindDialog(szName);
		if(pDialog != NULL)
		{
			return pDialog;
		}
	}
	return NULL;
}

CMapKit::TMAP* CSightKit::FindMap(LPCTSTR szName)
{
	list<MKIT*>::iterator it;
	it = m_MapKits.begin();
	while(it != m_MapKits.end())
	{
		MKIT* pMkit = *it++;
		TMAP* pMap = pMkit->FindMap(szName);
		if(pMap != NULL)
		{
			return pMap;
		}
	}
	return NULL;
}

static inline bool IsPowerOf2(int n)
{
	  if (n<=0)  return false;
	  return (n & (n-1))==0;
}

static inline int NextPowerOf2(int v)
{
	v--;
	v |= v >> 1;
	v |= v >> 2;
	v |= v >> 4;
	v |= v >> 8;
	v |= v >> 16;
	v++;
	return v;
}

BOOL CSightKit::SaveDat(LPCTSTR szFileName, int nFiles)
{
	try
	{
		typedef CSpriteKit::IMAGE IMAGE;
		typedef CSpriteKit::FCLIP FCLIP;
		typedef CSpriteKit::FRAME FRAME;
		typedef CSpriteKit::ACTION ACTION;
		typedef CDialogKit::CITEM CITEM;
		typedef CDialogKit::DITEM DITEM;

		list<IMAGE*> ImageList;
		list<FCLIP*> FclipList;
		list<FRAME*> FrameList;
		list<ACTION*> ActionList;
		list<SPRITE*> SpriteList;

		if(m_SprKits.size() > 0)
		{
			list<SKIT*>::iterator it;
			it = m_SprKits.begin();
			while(it != m_SprKits.end())
			{
				SKIT* pSkit = *it++;

				pSkit->JoinTo(ImageList);
				pSkit->JoinTo(FclipList);
				pSkit->JoinTo(FrameList);
				pSkit->JoinTo(ActionList);
				pSkit->JoinTo(SpriteList);
			}
		}

		typedef CDialogKit::CONTROL CONTROL;

		list<CONTROL*> ControlList;
		list<DIALOG*> DialogList;
		
		if(m_DlgKits.size() > 0)
		{
			list<DKIT*>::iterator it;
			it = m_DlgKits.begin();
			while(it != m_DlgKits.end())
			{
				DKIT* pDkit = *it++;

				//list<CDialogKit::SKIT*>::iterator lit;
				//lit = pDkit->m_SprKits.begin();
				//while(lit != pDkit->m_SprKits.end())
				//{
				//	CDialogKit::SKIT* pSkit = *lit++;
				//	pSkit->JoinTo(ImageList);
				//	pSkit->JoinTo(FclipList);
				//	pSkit->JoinTo(FrameList);
				//	pSkit->JoinTo(ActionList);
				//	pSkit->JoinTo(SpriteList);
				//}

				pDkit->JoinTo(ControlList);
				pDkit->JoinTo(DialogList);
			}
		}

		typedef CMapKit::TMAP TMAP;
		typedef CMapKit::TPOS TPOS;
		typedef CMapKit::TILE TILE;
		typedef CMapKit::TIMG TIMG;

		list<TMAP*> MapList;
		if(m_Groups.size() > 0)
		{
			SINT idx = 0;

			list<GROUP*>::iterator it;
			it = m_Groups.begin();
			while(it != m_Groups.end())
			{
				GROUP*	pGroup = *it++;
				
				list<TOBJECT*>::iterator lit;
				lit = pGroup->ObjList.begin();
				while(lit != pGroup->ObjList.end())
				{
					TOBJECT* pObj = *lit++;
					if(pObj->nType == tMap)
					{
						if(pObj->pMap)
						{
							pObj->pMap->idx = idx++;
							MapList.push_back(pObj->pMap);
						}
					}
				}
			}
		}

		CFile file(szFileName, CFile::modeCreate|CFile::modeWrite);

		using namespace SceneDat;

		SIGHT_HEAD Head;
		Head.dwMark = SIGHT_MARK;

		Head.nFiles = nFiles;

		Head.nStyle = m_nStyles;
		Head.pStyle = sizeof(Head);
		Head.nImage = ImageList.size();
		Head.pImage = Head.pStyle + sizeof(SceneDat::STYLE)*(Head.nStyle);
		Head.nFclip = FclipList.size();
		Head.pFclip = Head.pImage + sizeof(SceneDat::IMG)*(Head.nImage);
		Head.nFrame = FrameList.size();
		Head.pFrame = Head.pFclip + sizeof(SceneDat::FCLIP)*(Head.nFclip);
		Head.nAction = ActionList.size();
		Head.pAction = 0;
		Head.nSprite = SpriteList.size();
		Head.pSprite = 0;
		Head.nControl = ControlList.size();
		Head.pControl = 0;
		Head.nDialog = DialogList.size();
		Head.pDialog = 0;
		Head.nMap = MapList.size();
		Head.pMap = 0;

		if(Head.nFrame >= 0)
		{
			int nFclip = 0;
			list<FRAME*>::iterator it;
			it = FrameList.begin();
			while(it != FrameList.end())
			{
				FRAME* pFrame = *it++;

				nFclip += pFrame->FclipList.size();
			}
			int nSize = Head.nFrame * sizeof(SceneDat::INT) // delay
					+ Head.nFrame * sizeof(SceneDat::INT) // nFclip
					+ nFclip * sizeof(SceneDat::PTR);

			Head.pAction = Head.pFrame + nSize;
		}
		if(Head.nAction >= 0)
		{
			int nFrame = 0;
			list<ACTION*>::iterator it;
			it = ActionList.begin();
			while(it != ActionList.end())
			{
				ACTION* pAction = *it++;

				nFrame += pAction->FrameList.size();
			}
			int nSize = Head.nAction * sizeof(SceneDat::PTR)
					+ Head.nAction * (sizeof(SceneDat::INT) * 2)
					+ nFrame * sizeof(SceneDat::PTR);

			Head.pSprite = Head.pAction + nSize;
		}
		if(Head.nSprite >= 0)
		{
			int nAction = 0;
			list<SPRITE*>::iterator it;
			it = SpriteList.begin();
			while(it != SpriteList.end())
			{
				SPRITE* pSprite = *it++;

				nAction += pSprite->ActionList.size();
			}
			int nSize = Head.nSprite * sizeof(SceneDat::PTR)
					+ Head.nSprite * (sizeof(SceneDat::INT) * 2)
					+ nAction * sizeof(SceneDat::PTR);

			Head.pControl = Head.pSprite + nSize;
		}
		if(Head.nControl >= 0)
		{
			int nItem = 0;
			list<CONTROL*>::iterator it;
			it = ControlList.begin();
			while(it != ControlList.end())
			{
				CONTROL* pControl = *it++;

				nItem += pControl->ItemList.size();
			}
			int nSize = Head.nControl * sizeof(SceneDat::INT)
					+ Head.nControl * sizeof(SceneDat::INT)
					+ nItem * sizeof(SceneDat::CITEM);

			Head.pDialog = Head.pControl + nSize;
		}
		if(Head.nDialog >= 0)
		{
			int nItem = 0;
			list<DIALOG*>::iterator it;
			it = DialogList.begin();
			while(it != DialogList.end())
			{
				DIALOG* pDialog = *it++;
				nItem += pDialog->ItemList.size();
			}
			int nSize = Head.nDialog * sizeof(SceneDat::PTR)
				+ Head.nDialog * sizeof(SceneDat::INT)
				+ nItem * sizeof(SceneDat::DITEM);

			Head.pMap = Head.pDialog + nSize;
		}

		file.Write(&Head, sizeof(Head));

		if(Head.nStyle > 0)
		{
			file.Write(m_pStyles, sizeof(SceneDat::STYLE)*Head.nStyle);
		}

		if(ImageList.size() > 0)
		{
			ASSERT(Head.pImage == file.GetPosition());

			list<IMAGE*>::iterator it;
			it = ImageList.begin();
			while(it != ImageList.end())
			{
				IMAGE* pImage = *it++;

				SceneDat::IMG Img;
				
				Img.nType = pImage->nType;
				Img.nIdx = pImage->idx;

				Img.x = pImage->x;
				Img.y = pImage->y;
				Img.cx = pImage->cx;
				Img.cy = pImage->cy;

				pImage->ptr = file.GetPosition();

				file.Write(&Img, sizeof(IMG));
			}
		}
		if(FclipList.size() > 0)
		{
			ASSERT(Head.pFclip == file.GetPosition());

			list<FCLIP*>::iterator it;
			it = FclipList.begin();
			while(it != FclipList.end())
			{
				FCLIP* pFclip = *it++;
				
				SceneDat::FCLIP Fclip;
				Fclip.fAngle = pFclip->fAngle;
				Fclip.nPosX = pFclip->nPosX;
				Fclip.nPosY = pFclip->nPosY;
				Fclip.nXRep = pFclip->nXRep;
				Fclip.nYRep = pFclip->nYRep;
				Fclip.nOffX = pFclip->nOffX;
				Fclip.nOffY = pFclip->nOffY;
				
				Fclip.pImage = pFclip->pImage->ptr;

				pFclip->ptr = file.GetPosition();

				file.Write(&Fclip, sizeof(Fclip));
			}
		}
		if(FrameList.size() > 0)
		{
			int nMaxFclip = 0;
			list<FRAME*>::iterator it;
			it = FrameList.begin();
			while(it != FrameList.end())
			{
				FRAME* pFrame = *it++;

				int nFclip = pFrame->FclipList.size();
				if(nMaxFclip < nFclip)
				{
					nMaxFclip = nFclip;
				}
			}
			UINT nBuffer = sizeof(SceneDat::FRAME) 
					+ nMaxFclip*sizeof(SceneDat::PTR);

			BYTE* pBuffer = new BYTE[nBuffer];

			it = FrameList.begin();
			while(it != FrameList.end())
			{
				FRAME* pFrame = *it++;

				SceneDat::FRAME* pWrite = (SceneDat::FRAME*)pBuffer;
				pWrite->nDelay = pFrame->nDelay;
				pWrite->nFclip = pFrame->FclipList.size();

				int i = 0;

				list<FCLIP*>::iterator lit;
				lit = pFrame->FclipList.begin();
				while(lit != pFrame->FclipList.end())
				{
					FCLIP* pFclip = *lit++;
					pWrite->pFclip[i] = pFclip->ptr;
					i++;
				}

				pFrame->ptr = file.GetPosition();

				int nSize = sizeof(SceneDat::FRAME)
					+ (pWrite->nFclip-1)*(sizeof(SceneDat::PTR));
				
				file.Write(pWrite, nSize);
			}

			delete[] pBuffer;
		}
		if(ActionList.size() > 0)
		{
			SceneDat::PTR ptr = file.GetPosition();

			ASSERT(ptr == Head.pAction);

			SceneDat::PTR* ptrArray = new SceneDat::PTR[Head.nAction];

			ptr += sizeof(SceneDat::PTR)*Head.nAction;

			int nMaxFrame = 0;
			int i = 0;

			list<ACTION*>::iterator it;
			it = ActionList.begin();
			while(it != ActionList.end())
			{
				ACTION* pAction = *it++;

				int nFrame = pAction->FrameList.size();

				ptrArray[i] = ptr;

				pAction->ptr = ptr;
				pAction->idx = i;

				i++;

				if(nFrame > nMaxFrame)
					nMaxFrame = nFrame;

				ptr += sizeof(SceneDat::INT) // nFlags 
					+ sizeof(SceneDat::INT)  // nFrame
					+ sizeof(PTR)*nFrame;
			}

			file.Write(ptrArray, sizeof(SceneDat::PTR)*Head.nAction);

			UINT nBuffer = sizeof(SceneDat::INT) // nFlags
						+ sizeof(SceneDat::INT)  // nFrame
						+ sizeof(PTR)*nMaxFrame;
			BYTE* pBuffer = new BYTE[nBuffer];


			it = ActionList.begin();
			while(it != ActionList.end())
			{
				ACTION* pAction = *it++;

				int nFrame = pAction->FrameList.size();

				SceneDat::ACTION* pWrite = (SceneDat::ACTION*)pBuffer;
				pWrite->nFlags = pAction->nFlags;
				pWrite->nFrame = nFrame;
				
				int i = 0;
				list<FRAME*>::iterator lit;
				lit = pAction->FrameList.begin();
				while(lit != pAction->FrameList.end())
				{
					FRAME* pFrame = *lit++;
					pWrite->pFrame[i] = pFrame->ptr;
					i++;
				}

				int nSize = sizeof(SceneDat::ACTION)
					+ (pWrite->nFrame-1)*sizeof(SceneDat::PTR);

				file.Write(pWrite, nSize);
				
			}

			delete[] pBuffer;
			delete[] ptrArray;
		}
		if(SpriteList.size() > 0)
		{
			SceneDat::PTR ptr = file.GetPosition();

			ASSERT(ptr == Head.pSprite);

			SceneDat::PTR* ptrArray = new SceneDat::PTR[Head.nSprite];

			ptr += sizeof(SceneDat::PTR)*Head.nSprite;

			int nMaxAction = 0;
			int i = 0;

			list<SPRITE*>::iterator it;
			it = SpriteList.begin();
			while(it != SpriteList.end())
			{
				SPRITE* pSprite = *it++;

				int nAction = pSprite->ActionList.size();

				ptrArray[i] = ptr;

				pSprite->ptr = ptr;
				pSprite->idx = i;

				i++;

				if(nAction > nMaxAction)
					nMaxAction = nAction;

				ptr += sizeof(SceneDat::INT) // nFlags 
					+ sizeof(SceneDat::INT)  // nAction
					+ sizeof(PTR)*nAction;
			}

			file.Write(ptrArray, sizeof(SceneDat::PTR)*Head.nSprite);

			UINT nBuffer = sizeof(SceneDat::INT) // nFlags
						+ sizeof(SceneDat::INT)  // nAction
						+ sizeof(PTR)*nMaxAction;
			BYTE* pBuffer = new BYTE[nBuffer];


			it = SpriteList.begin();
			while(it != SpriteList.end())
			{
				SPRITE* pSprite = *it++;

				int nAction = pSprite->ActionList.size();

				SceneDat::SPRITE* pWrite = (SceneDat::SPRITE*)pBuffer;
				pWrite->nFlags = pSprite->nFlags;
				pWrite->nAction = nAction;
				
				int i = 0;
				list<ACTION*>::iterator lit;
				lit = pSprite->ActionList.begin();
				while(lit != pSprite->ActionList.end())
				{
					ACTION* pAction = *lit++;
					pWrite->pAction[i] = pAction->ptr;
					i++;
				}

				int nSize = sizeof(SceneDat::SPRITE)
					+ (pWrite->nAction-1)*sizeof(SceneDat::PTR);

				file.Write(pWrite, nSize);
				
			}

			delete[] pBuffer;
			delete[] ptrArray;
		}
		if(ControlList.size() > 0)
		{
			ASSERT(Head.pControl == file.GetPosition());

			list<CONTROL*>::iterator it;
			it = ControlList.begin();
			while(it != ControlList.end())
			{
				CONTROL* pControl = *it++;

				pControl->ptr = file.GetPosition();

				SceneDat::INT nType = pControl->GetType();

				file.Write(&nType, sizeof(SceneDat::INT));

				SceneDat::INT nItem = pControl->ItemList.size();
				file.Write(&nItem, sizeof(SceneDat::INT));

				list<CITEM*>::iterator lit;
				lit = pControl->ItemList.begin();
				while(lit != pControl->ItemList.end())
				{
					CITEM* pItem = *lit++;

					SceneDat::CITEM cItem;
					cItem.nPosX = pItem->nPosX;
					cItem.nPosY = pItem->nPosY;
					cItem.nType = pItem->nType;
					if(pItem->nType == CDialogKit::tSprite)
					{
						cItem.pItem = pItem->pSprite->ptr;
					}
					else
					{
						cItem.pItem = pItem->pControl->ptr;
						cItem.nType = pItem->pControl->GetType();
					}
					file.Write(&cItem, sizeof(cItem));
				}
			}
		}
		if(DialogList.size() > 0)
		{
			SceneDat::PTR ptr = file.GetPosition();

			ASSERT(ptr == Head.pDialog);

			SceneDat::PTR* ptrArray = new SceneDat::PTR[Head.nDialog];

			ptr += sizeof(SceneDat::PTR)*Head.nDialog;

			int nMaxItem = 0;
			int i = 0;

			list<DIALOG*>::iterator it;
			it = DialogList.begin();
			while(it != DialogList.end())
			{
				DIALOG* pDialog = *it++;

				int nItem = pDialog->ItemList.size();

				ptrArray[i] = ptr;

				pDialog->ptr = ptr;
				pDialog->idx = i;

				i++;

				if(nItem > nMaxItem)
					nMaxItem = nItem;

				ptr += sizeof(SceneDat::INT) + sizeof(SceneDat::DITEM)*nItem;
			}

			file.Write(ptrArray, sizeof(SceneDat::PTR)*Head.nDialog);

			UINT nBuffer = sizeof(SceneDat::INT) + sizeof(SceneDat::DITEM)*nMaxItem;
			BYTE* pBuffer = new BYTE[nBuffer];


			it = DialogList.begin();
			while(it != DialogList.end())
			{
				DIALOG* pDialog = *it++;

				int nItem = pDialog->ItemList.size();

				SceneDat::DIALOG* pWrite = (SceneDat::DIALOG*)pBuffer;
				pWrite->nItem = nItem;
				
				int i = 0;
				list<DITEM*>::iterator lit;
				lit = pDialog->ItemList.begin();
				while(lit != pDialog->ItemList.end())
				{
					DITEM* pItem = *lit++;
					pWrite->pItem[i].nPosX = pItem->nPosX;
					pWrite->pItem[i].nPosY = pItem->nPosY;
					pWrite->pItem[i].nNtfy = pItem->nNtfy;
					pWrite->pItem[i].pItem = pItem->pCtrl->ptr;

					pItem->idx = i;

					i++;
				}
				int nSize = sizeof(SceneDat::DIALOG)
					+ (pWrite->nItem-1)*sizeof(SceneDat::DITEM);

				file.Write(pWrite, nSize);
				
			}

			delete[] pBuffer;
			delete[] ptrArray;
		}
		if(MapList.size() > 0)
		{
			SceneDat::PTR ptr = file.GetPosition();

			ASSERT(ptr == Head.pMap);

			SceneDat::PTR* ptrArray = new SceneDat::PTR[Head.nMap];

			ptr += sizeof(SceneDat::PTR)*Head.nMap;

			int nMaxSize = 0;
			int i = 0;

			list<TMAP*>::iterator it;
			it = MapList.begin();
			while(it != MapList.end())
			{
				TMAP* pMap = *it++;

				ptrArray[i] = ptr;

				int nPos = pMap->PosList.size();
				int nImg = pMap->ImgList.size();
				int nTile = pMap->TileList.size();

				int nSize = sizeof(SceneDat::MAP)
					+ nImg * sizeof(SceneDat::TIMG)
					+ nPos * sizeof(SceneDat::POS)
					+ nTile * sizeof(SceneDat::TILE);

				ptr += nSize;

				if(nSize > nMaxSize)
					nMaxSize = nSize;
			}

			file.Write(ptrArray, sizeof(SceneDat::PTR)*Head.nMap);

			BYTE* pBuffer = new BYTE[nMaxSize];

			it = MapList.begin();
			while(it != MapList.end())
			{
				TMAP* pMap = *it++;

				SceneDat::PTR ptr = file.GetPosition();

				SceneDat::MAP* pWriteMap = (SceneDat::MAP*)pBuffer;
	
				pWriteMap->nType = 0;

				pWriteMap->nImg = pMap->ImgList.size();
				pWriteMap->nPos = pMap->PosList.size();
				pWriteMap->nTile = pMap->TileList.size();

				pWriteMap->pImg = ptr + sizeof(SceneDat::MAP);
				pWriteMap->pPos = pWriteMap->pImg 
					+ pWriteMap->nImg * sizeof(SceneDat::TIMG);
				pWriteMap->pTile = pWriteMap->pPos
					+ pWriteMap->nPos * sizeof(SceneDat::POS);


				SceneDat::TIMG* pImgArray = (SceneDat::TIMG*)
					(pWriteMap + 1);
				SceneDat::POS* pPosArray = (SceneDat::POS*)
					(pImgArray + pWriteMap->nImg);
				SceneDat::TILE* pTileArray = (SceneDat::TILE*)
					(pPosArray + pWriteMap->nPos);

				int i = 0;

				list<TIMG*>::iterator tit;
				tit = pMap->ImgList.begin();
				while(tit != pMap->ImgList.end())
				{
					TIMG* pImg = *tit++;

					pImg->idx  = i;

					strcpy(pImgArray[i].szImg, pImg->szFile);
					pImgArray[i].x = pImg->x;
					pImgArray[i].y = pImg->y;
					pImgArray[i].cx = pImg->cx;
					pImgArray[i].cy = pImg->cy;

					i++;
				}

				i = 0;

				list<TPOS*>::iterator lit;
				lit = pMap->PosList.begin();
				while(lit != pMap->PosList.end())
				{
					TPOS* pPos = *lit++;

					pPosArray[i].x = pPos->x;
					pPosArray[i].y = pPos->y;
					pPosArray[i].cx = pPos->cx;
					pPosArray[i].cy = pPos->cy;

					i++;
				}

				i = 0;

				list<TILE*>::iterator iit;
				iit = pMap->TileList.begin();
				while(iit != pMap->TileList.end())
				{
					TILE* pTile = *iit++;

					pTileArray[i].idx = pTile->pImage->idx;
					pTileArray[i].x = pTile->x;
					pTileArray[i].y = pTile->y;

					i++;
				}

				int nSize = sizeof(SceneDat::MAP)
					+ pWriteMap->nImg * sizeof(SceneDat::TIMG)
					+ pWriteMap->nPos * sizeof(SceneDat::POS)
					+ pWriteMap->nTile * sizeof(SceneDat::TILE);

				file.Write(pWriteMap, nSize);
			}
			delete[] pBuffer;
			delete[] ptrArray;
		}

		file.Close();

		return TRUE;
	}
	catch(CException* e)
	{
		e->ReportError();
		e->Delete();
	}
	return FALSE;
}

BOOL CSightKit::Build(LPCTSTR szOutput, int iSight, CString& szMaps, CString& szSprites, CString& szDialogs)
{
	CString szName = m_szName;

	TCHAR szSaveFile[MAX_PATH];
	_tcscpy(szSaveFile, szOutput);
	PathAppend(szSaveFile, szName);

	CString szPng(szSaveFile);
	CString szDat(szSaveFile);

	szDat += SIGHT_EXT;

	int nFiles = SavePng(szPng);
	SaveDat(szDat, nFiles);

	// generate codes
	if(m_Groups.size() > 0)
	{
		list<GROUP*>::iterator it;
		it = m_Groups.begin();
		while(it != m_Groups.end())
		{
			GROUP* pGroup = *it++;

			list<TOBJECT*>::iterator lit;
			lit = pGroup->ObjList.begin();
			while(lit != pGroup->ObjList.end())
			{
				TOBJECT* pObj = *lit++;

				if(pObj->nType == tMap)
				{
					SINT d = iSight << 16;
					d |= pObj->pMap->idx;

					CString szDef;
					szDef.Format(_T("\t\t%s = 0x%X,\r\n"),
						pObj->pMap->szName, d);

					szMaps += szDef;

				}
				else if(pObj->nType == tSprite)
				{
					SINT d = iSight << 16;
					d |= pObj->pSprite->idx;

					CString szDef;
					szDef.Format(_T("\t\t%s = 0x%X,\r\n"),
						pObj->pSprite->szName, d);

					szSprites += szDef;
				}
				else if(pObj->nType == tDialog)
				{
					SINT d = iSight << 16;
					d |= pObj->pDialog->idx;

					CString szDlg;
					szDlg.Format(_T("\t\t%s = 0x%X,\r\n"),
						pObj->pDialog->szName, d);
					szDialogs += szDlg;

					pObj->pDialog->Build(szOutput);
				}
			}
		}
	}

	return TRUE;
}

SINT CSightKit::SavePng(LPCTSTR szOutput)
{
	set<IMAGE*> ImgSet;

	if(m_SprKits.size() > 0)
	{
		list<SKIT*>::iterator it;
		it = m_SprKits.begin();
		while(it != m_SprKits.end())
		{
			SKIT* pSkit = *it++;
			pSkit->GetImages(ImgSet);
		}
	}
	if(m_DlgKits.size() > 0)
	{
		list<DKIT*>::iterator it;
		it = m_DlgKits.begin();
		while(it != m_DlgKits.end())
		{
			DKIT* pDkit = *it++;
			pDkit->GetImages(ImgSet);
		}
	}
	
	list<SIMG> ImgList;
	list<STYLE> StyleList;

	set<IMAGE*>::iterator sit;
	sit = ImgSet.begin();
	while(sit != ImgSet.end())
	{
		IMAGE* pImg = *sit++;
		if(pImg->nType == SceneDat::eImage)
		{
			SIMG sImg(pImg);
			ImgList.push_back(sImg);
		}
		else
		{
			STYLE sStyle(pImg);
			StyleList.push_back(sStyle);
		}
	}

	m_nStyles = 0;
	delete[] m_pStyles;
	m_pStyles = NULL;

	if(StyleList.size() > 0)
	{
		STYLE sPrev(NULL);

		int nCount = StyleList.size();
		m_pStyles = new SceneDat::STYLE[nCount];

		list<STYLE>::iterator it;
		it = StyleList.begin();
		while(it != StyleList.end())
		{
			STYLE s = *it++;
			if(sPrev.pImg != NULL)
			{
				if( s.nHash == sPrev.nHash &&
					memcmp(&(s.pImg->style), &(sPrev.pImg->style),
					sizeof(SceneDat::STYLE)) == 0 )
				{
					s.pImg->idx = sPrev.pImg->idx;
				}
				else
				{
					s.pImg->idx = m_nStyles;
					m_pStyles[m_nStyles] = s.pImg->style;
					m_nStyles++;
				}
			}
			else
			{
				s.pImg->idx = m_nStyles;
				m_pStyles[m_nStyles] = s.pImg->style;
				m_nStyles++;
			}
			sPrev = s;
		}
	}
	
	return SaveImages(ImgList, szOutput);
}

SINT CSightKit::SaveImages(list<SIMG>& ImgList, LPCTSTR szOutput)
{
	SINT nImage = 0;

	ImgList.sort();

	while(ImgList.size() > 0)
	{
		list<IMAGE*> PicList;

		list<SIMG>::iterator it;
		it = ImgList.begin();
		while(it != ImgList.end())
		{
			list<SIMG>::iterator rit = it++;
			SIMG& rImg = *rit;

			if(MakeImgAdd(PicList, rImg.pImg, 512, 512))
			{
				ImgList.erase(rit);
			}
		}

		if(PicList.size() > 0)
		{
			TCHAR szFile[MAX_PATH];
			_stprintf(szFile, _T("%s%d.png"), szOutput, nImage);

			SavePng(szFile, PicList, nImage);

			nImage++;

			PicList.clear();
		}
	}
	
	return nImage;
}

BOOL CSightKit::MakeImgAdd(list<IMAGE*>& PicList, IMAGE* pAdd, int xmax, int ymax)
{
	if(PicList.size() > 0)
	{
		list<IMAGE*>::iterator pit;
		pit = PicList.begin();
		while(pit != PicList.end())
		{
			IMAGE* pImage = *pit++;

			pAdd->x = pImage->x + pImage->cx;
			pAdd->y = pImage->y;

			if( pAdd->x + pAdd->cx <= xmax &&
				pAdd->y + pAdd->cy <= ymax )
			{
				if(!IsCrossed(PicList, pAdd))
				{
					PicList.push_back(pAdd);
					return TRUE;
				}
			}

			pAdd->y = pImage->y + pImage->cy;

			if( pAdd->x + pAdd->cx <= xmax &&
				pAdd->y + pAdd->cy <= ymax )
			{
				if(!IsCrossed(PicList, pAdd))
				{
					PicList.push_back(pAdd);
					return TRUE;
				}
			}

			pAdd->x = pImage->x;

			if( pAdd->x + pAdd->cx <= xmax &&
				pAdd->y + pAdd->cy <= ymax )
			{
				if(!IsCrossed(PicList, pAdd))
				{
					PicList.push_back(pAdd);
					return TRUE;
				}
			}

		}
		return FALSE;
	}
	else
	{
		pAdd->x = 0;
		pAdd->y = 0;

		PicList.push_back(pAdd);
		return TRUE;
	}
}

inline bool CSightKit::IsCrossed(IMAGE* pImg1, IMAGE* pImg2)
{
	if(pImg1 != pImg2)
	{
		int rx1 = pImg1->x + pImg1->cx;
		int by1 = pImg1->y + pImg1->cy;

		int rx2 = pImg2->x + pImg2->cx;
		int by2 = pImg2->y + pImg2->cy;

		if(pImg1->x >= rx2)
			return false;

		if(rx1 <= pImg2->x)
			return false;

		if(pImg1->y >= by2)
			return false;

		if(by1 <= pImg2->y)
			return false;

	}
	return true;
}

inline bool CSightKit::IsCrossed(list<IMAGE*>& PicList, IMAGE* pTest)
{
	list<IMAGE*>::iterator it;
	it = PicList.begin();
	while(it != PicList.end())
	{
		IMAGE* pImg = *it++;

		if(IsCrossed(pImg, pTest))
		{
			return true;
		}
	}
	return false;
}


BOOL CSightKit::SavePng(LPCTSTR szFileName, list<IMAGE*>& PicList, int nImgId)
{
	int nWidth = 0;
	int nHeight = 0;

	list<IMAGE*>::iterator it;
	it = PicList.begin();
	while(it != PicList.end())
	{
		IMAGE* pImg = *it++;

		int x = pImg->x + pImg->cx;
		int y = pImg->y + pImg->cy;

		if(nWidth < x)
			nWidth = x;
		if(nHeight < y)
			nHeight = y;
	}

	if(!IsPowerOf2(nWidth))
		nWidth = NextPowerOf2(nWidth);
	if(!IsPowerOf2(nHeight))
		nHeight = NextPowerOf2(nHeight);

	CxImage xImage;
	if(xImage.Create(nWidth, nHeight, 24, CXIMAGE_FORMAT_PNG))
	{
		xImage.AlphaCreate();
		xImage.AlphaSet(0);

		it = PicList.begin();
		while(it != PicList.end())
		{
			IMAGE* pImg = *it++;

			pImg->idx = nImgId;

			int y = nHeight - pImg->y - pImg->cy;

			xImage.SubImage(pImg->xImage, pImg->x, y, true);
		}
		
		return xImage.Save(szFileName, CXIMAGE_FORMAT_PNG);
	}

	return FALSE;
}
